package cn.btks.commonserver.util.poi;

import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.config.Configure;
import com.deepoove.poi.config.ConfigureBuilder;
import com.deepoove.poi.policy.HackLoopTableRenderPolicy;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.xwpf.model.XWPFHeaderFooterPolicy;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.xmlbeans.XmlOptions;
import org.apache.xmlbeans.impl.xb.xmlschema.SpaceAttribute;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;

import java.io.*;
import java.util.*;

public class PoitlUtil {

    /**
     * 填充人员模板
     *
     * @param docPath 模板路径
     * @param detPath 生成文件路径
     * @param tagName 模板table中标签名
     * @param object  绑定table对象
     */
    public static void GenerateTable(String docPath, String detPath, String tagName, Object object) throws IOException {
        HackLoopTableRenderPolicy policy = new HackLoopTableRenderPolicy();
        Configure config = Configure.newBuilder().bind(tagName, policy).build();

        XWPFTemplate template = XWPFTemplate.compile(docPath, config).render(new HashMap<String, Object>() {{
            put(tagName, object);
        }});
        template.writeToFile(detPath);
    }

    /**
     * 填充多表模板
     *
     * @param docPath 模板路径
     * @param detPath 生成文件路径
     * @param map     表格列表对象
     * @throws IOException
     */
    public static void GenerateTable(String docPath, String detPath, Map<String, Object> map) throws IOException {
        HackLoopTableRenderPolicy policy = new HackLoopTableRenderPolicy();
        ConfigureBuilder configureBuilder = Configure.newBuilder();
        Set<String> sets = map.keySet();
        for (String keyItem : sets) {
            configureBuilder.bind(keyItem, policy);
        }
        Configure configure = configureBuilder.build();


        XWPFTemplate template = XWPFTemplate.compile(docPath, configure).render(map);
        template.writeToFile(detPath);
    }

    /**
     * 根据javebeen添加注解@Name来生成模板
     *
     * @param docPath 模板路径
     * @param detPath 生成文件路径
     * @param object  传递过来的对象
     * @throws IOException
     */
    public static void GenerateTemplate(String docPath, String detPath, Object object) throws IOException {
        ConfigureBuilder builder = Configure.newBuilder();
        builder.buildGramer("${", "}");
        XWPFTemplate template = XWPFTemplate.compile(docPath, builder.build()).render(object);
//        XWPFTemplate template = XWPFTemplate.compile(docPath,builder.build()).render(object);
        template.writeToFile(detPath);
    }

    public static void GenerateTemplate1(InputStream inputStream, String detPath, Object object) throws IOException {
        try{
            ConfigureBuilder builder = Configure.newBuilder();
            builder.buildGramer("${", "}");
            XWPFTemplate template = XWPFTemplate.compile(inputStream, builder.build()).render(object);
//        XWPFTemplate template = XWPFTemplate.compile(docPath,builder.build()).render(object);
            template.writeToFile(detPath);
        }catch (Exception e){
            System.out.println(e);
        }
    }

    /**
     * 合并Word文档
     *
     * @param fileList Word文件列表
     * @param srcPath  合并后生成的文件路径
     * @throws Exception
     */
    public static void MergeDoc(List<File> fileList, String srcPath) throws Exception {
        File newFile = new File(srcPath);
        if (!newFile.exists()) {
            newFile.createNewFile();
        }
        int[] indexs = new int[]{0, 1, 2, 5, 13};//需要添加分页符的位置
        try {
            OutputStream dest = new FileOutputStream(newFile);
            ArrayList<XWPFDocument> documentList = new ArrayList<>();
            XWPFDocument doc = null;
            for (int i = 0; i < fileList.size(); i++) {
                FileInputStream in = new FileInputStream(fileList.get(i).getPath());
                OPCPackage open = OPCPackage.open(in);
                XWPFDocument document = new XWPFDocument(open);
                documentList.add(document);
            }
            for (int i = 0; i < documentList.size(); i++) {
                doc = documentList.get(0);
                if (i != 0) {
                    for (int indexItem : indexs) {
                        if (indexItem == i && i != documentList.size() - 1) {
                            //每部分换页
//                        XWPFRun run2=documentList.get(i).getLastParagraph().createRun();
//                        run2.addBreak(BreakType.PAGE);
                            documentList.get(i).createParagraph().setPageBreak(true);
                            break;
                        }
                    }
                    appendBody(doc, documentList.get(i));
                } else {
                    documentList.get(i).createParagraph().setPageBreak(true);
                }
            }
            doc.createParagraph().setPageBreak(true);
            doc.write(dest);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void appendBody(XWPFDocument src, XWPFDocument append) throws Exception {
        CTBody src1Body = src.getDocument().getBody();
        CTBody src2Body = append.getDocument().getBody();

        List<XWPFPictureData> allPictures = append.getAllPictures();
        // 记录图片合并前及合并后的ID
        Map<String, String> map = new HashMap();
        for (XWPFPictureData picture : allPictures) {
            String before = append.getRelationId(picture);
            //将原文档中的图片加入到目标文档中
            String after = src.addPictureData(picture.getData(), Document.PICTURE_TYPE_PNG);
            map.put(before, after);
        }

        appendBody(src1Body, src2Body, map);

    }

    private static void appendBody(CTBody src, CTBody append, Map<String, String> map) throws Exception {
        XmlOptions optionsOuter = new XmlOptions();
        optionsOuter.setSaveOuter();
        String appendString = append.xmlText(optionsOuter);

        String srcString = src.xmlText();
        String prefix = srcString.substring(0, srcString.indexOf(">") + 1);
        String lackStr = " xmlns:wp14=\"http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing\"";
        int result = srcString.indexOf("http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing");
        if (result < 0) {
            prefix = srcString.substring(0, srcString.indexOf(">")) + lackStr + ">";
        }
//        prefix = "<xml-fragment xmlns:wpc=\"http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas\"
//        xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\"
//        xmlns:o=\"urn:schemas-microsoft-com:office:office\" xmlns:r=\"http://schemas.openxmlformats
//        .org/officeDocument/2006/relationships\" xmlns:m=\"http://schemas.openxmlformats
//        .org/officeDocument/2006/math\" xmlns:v=\"urn:schemas-microsoft-com:vml\" xmlns:wp14=\"http://schemas
//        .microsoft.com/office/word/2010/wordprocessingDrawing\" xmlns:wp=\"http://schemas.openxmlformats
//        .org/drawingml/2006/wordprocessingDrawing\" xmlns:w=\"http://schemas.openxmlformats
//        .org/wordprocessingml/2006/main\" xmlns:w14=\"http://schemas.microsoft.com/office/word/2010/wordml\"
//        xmlns:w10=\"urn:schemas-microsoft-com:office:word\" xmlns:w15=\"http://schemas.microsoft
//        .com/office/word/2012/wordml\" xmlns:wpg=\"http://schemas.microsoft
//        .com/office/word/2010/wordprocessingGroup\" xmlns:wpi=\"http://schemas.microsoft
//        .com/office/word/2010/wordprocessingInk\" xmlns:wne=\"http://schemas.microsoft
//        .com/office/word/2006/wordml\" xmlns:wps=\"http://schemas.microsoft
//        .com/office/word/2010/wordprocessingShape\" xmlns:wpsCustomData=\"http://www.wps
//        .cn/officeDocument/2013/wpsCustomData\">";
        String mainPart = srcString.substring(srcString.indexOf(">") + 1, srcString.lastIndexOf("<"));
        String sufix = srcString.substring(srcString.lastIndexOf("<"));
        String addPart = appendString.substring(appendString.indexOf(">") + 1, appendString.lastIndexOf("<"));

        if (map != null && !map.isEmpty()) {
            //对xml字符串中图片ID进行替换
            for (Map.Entry<String, String> set : map.entrySet()) {
                addPart = addPart.replace(set.getKey(), set.getValue());
            }
        }
        //将两个文档的xml内容进行拼接
        CTBody makeBody = CTBody.Factory.parse(prefix + mainPart + addPart + sufix);

        src.set(makeBody);
    }

    /**
     * 设置页脚页数
     *
     * @param document 文件对象
     * @throws Exception
     */
    public static void SetFooter(XWPFDocument document) throws Exception {
        CTP ctp = CTP.Factory.newInstance();
        XWPFParagraph codePara = new XWPFParagraph(ctp, document);

        XWPFRun r1 = codePara.createRun();
        r1.setText("第");
        setXWPFRunStyle(r1, "宋体", 11);

        r1 = codePara.createRun();
        CTFldChar fldChar = r1.getCTR().addNewFldChar();
        fldChar.setFldCharType(STFldCharType.Enum.forString("begin"));

        r1 = codePara.createRun();
        CTText ctText = r1.getCTR().addNewInstrText();
        ctText.setStringValue("PAGE  \\* MERGEFORMAT");
        ctText.setSpace(SpaceAttribute.Space.Enum.forString("preserve"));


        setXWPFRunStyle(r1, "宋体", 11);

        fldChar = r1.getCTR().addNewFldChar();
        fldChar.setFldCharType(STFldCharType.Enum.forString("end"));

        r1 = codePara.createRun();
        r1.setText("页");
        setXWPFRunStyle(r1, "宋体", 11);


//        r1 = codePara.createRun();
//        fldChar = r1.getCTR().addNewFldChar();
//        fldChar.setFldCharType(STFldCharType.Enum.forString("begin"));
//
//        r1 = codePara.createRun();
//        ctText = r1.getCTR().addNewInstrText();
//        ctText.setStringValue("NUMPAGES  \\* MERGEFORMAT ");
//        ctText.setSpace(SpaceAttribute.Space.Enum.forString("preserve"));
//        r1.setFontSize(11);
//        rpr = r1.getCTR().isSetRPr() ? r1.getCTR().getRPr() : r1.getCTR().addNewRPr();
//        fonts = rpr.isSetRFonts() ? rpr.getRFonts() : rpr.addNewRFonts();
//        fonts.setAscii("宋体");
//        fonts.setEastAsia("宋体");
//        fonts.setHAnsi("宋体");
//
//        fldChar = r1.getCTR().addNewFldChar();
//        fldChar.setFldCharType(STFldCharType.Enum.forString("end"));
//
//        r1 = codePara.createRun();
//        r1.setText("页");
//        r1.setFontSize(11);
//        rpr = r1.getCTR().isSetRPr() ? r1.getCTR().getRPr() : r1.getCTR().addNewRPr();
//        fonts = rpr.isSetRFonts() ? rpr.getRFonts() : rpr.addNewRFonts();
//        fonts.setAscii("宋体");
//        fonts.setEastAsia("宋体");
//        fonts.setHAnsi("宋体");


        codePara.setAlignment(ParagraphAlignment.CENTER);
        codePara.setVerticalAlignment(TextAlignment.CENTER);
        codePara.setBorderTop(Borders.THICK);
        XWPFParagraph[] newparagraphs = new XWPFParagraph[1];
        newparagraphs[0] = codePara;


        CTSectPr sectPr = document.getDocument().getBody().addNewSectPr();
        XWPFHeaderFooterPolicy headerFooterPolicy = new XWPFHeaderFooterPolicy(document, sectPr);
        headerFooterPolicy.createFooter(STHdrFtr.DEFAULT, newparagraphs);
    }

    /**
     * 设置页脚的字体样式
     *
     * @param r1 段落元素
     */
    private static void setXWPFRunStyle(XWPFRun r1, String font, int fontSize) {
        r1.setFontSize(fontSize);
        CTRPr rpr = r1.getCTR().isSetRPr() ? r1.getCTR().getRPr() : r1.getCTR().addNewRPr();
        CTFonts fonts = rpr.isSetRFonts() ? rpr.getRFonts() : rpr.addNewRFonts();
        fonts.setAscii(font);
        fonts.setEastAsia(font);
        fonts.setHAnsi(font);
    }

    /**
     * 生成动态表格
     *
     * @param docPath 源文件路径
     * @param detPath 生成文件路径
     * @param map1    绑定表格数据映射
     * @param map2    绑定表格索引参数
     * @throws IOException
     */
    public static void GenerataDynamicTable(String docPath, String detPath, HashMap<String, Object> map1,
                                            HashMap<String, String> map2) throws IOException {
        ConfigureBuilder configureBuilder = Configure.newBuilder();
        Set<String> sets = map1.keySet();
        for (String keyItem : sets) {
            String[] indexAndNumber = map2.get(keyItem).split("&"); //exm:"1&5" 开始行为第1行，每行有5列数据
            configureBuilder.bind(keyItem, new DynamicTablePolicy(Integer.parseInt(indexAndNumber[0]),
                    Integer.parseInt(indexAndNumber[1])));
        }
        Configure configure = configureBuilder.build();
        XWPFTemplate template = XWPFTemplate.compile(docPath, configure).render(map1);
        template.writeToFile(detPath);
    }

    public static void GenerataDynamicTable(String docPath, String detPath, HashMap<String, Object> map1, HashMap<String
            , String> map2, HashMap<String, Object> map3) throws IOException {
        ConfigureBuilder configureBuilder = Configure.newBuilder();
        Set<String> sets = map1.keySet();
        Set<String> mergeSet = map3.keySet();
        for (String keyItem : sets) {
            String[] indexAndNumber = map2.get(keyItem).split("&"); //exm:"1&5" 开始行为第1行，每行有5列数据
            if (mergeSet.contains(keyItem)) {
                int columnIndex = (int) map3.get(keyItem+"ColumnIndex");
                int fromRow = (int) map3.get(keyItem+"FromRow");
                int toRow = (int) map3.get(keyItem+"ToRow");
                configureBuilder.bind(keyItem, new DynamicMergeTablePolicy(Integer.parseInt(indexAndNumber[0]),
                        Integer.parseInt(indexAndNumber[1]),columnIndex,fromRow,toRow,map3.get(keyItem)));
            } else {
                configureBuilder.bind(keyItem, new DynamicTablePolicy(Integer.parseInt(indexAndNumber[0]),
                        Integer.parseInt(indexAndNumber[1])));
            }
        }
        Configure configure = configureBuilder.build();
        XWPFTemplate template = XWPFTemplate.compile(docPath, configure).render(map1);
        template.writeToFile(detPath);
    }

}
